package com.fcg.flutter_kefu_plugin;

import java.lang.ref.WeakReference;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import androidx.annotation.NonNull;

import android.app.Activity;
import android.app.Application;
import android.os.Looper;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;

import com.hyphenate.chat.ChatClient;
import com.hyphenate.chat.Message;
import com.hyphenate.chat.Conversation;
import com.hyphenate.chat.ChatManager;
import com.hyphenate.helpdesk.callback.Callback;
import com.hyphenate.helpdesk.callback.ValueCallBack;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;

/**
 * FlutterKefuPlugin
 */
public class FlutterKefuPlugin implements FlutterPlugin, ActivityAware, MethodCallHandler, EventChannel.StreamHandler {
    /// The MethodChannel that will the communication between Flutter and native Android
    ///
    /// This local reference serves to register the plugin with the Flutter Engine and unregister it
    /// when the Flutter Engine is detached from the Activity
    private static final String TAG = "FlutterKefuPlugin";
    private MethodChannel mMethodChannel;
    private EventChannel mEventChannel;
    private static EventChannel.EventSink mEventSink;
    private Application mApplication;
    private WeakReference<Activity> mActivity;
    private final String IMAGE = "image";
    private final String LOCALURL = "localurl";
    private final String REMOTEURL = "remoteurl";
    private final String THUMBNAIL = "thumbnail";

    private ChatManager.MessageListener mMessageListener = new ChatManager.MessageListener() {
        @Override
        public void onMessage(List<Message> list) {
            //收到普通消息
            Log.d(TAG, "===========receiver message=========:" + list.toString());
            final JSONArray jsonArray = new JSONArray();
            JSONObject tempObject = null;
            if (list != null && list.size() > 0) {
                int count = list.size();
                for (int i = 0; i < count; i++) {
                    tempObject = new JSONObject();
                    try {
                        String content = list.get(i).body().toString();
                        if (TextUtils.isEmpty(content)) {
                            continue;
                        }
                        tempObject.put("from", list.get(i).from());
                        tempObject.put("to", list.get(i).to());
                        String type = list.get(i).getType() == null ? "TXT" : list.get(i).getType().name();
                        tempObject.put("type", type);
                        tempObject.put("msgTime", System.currentTimeMillis());
                        if (TextUtils.equals("txt", type.toLowerCase())) {
                            String regex = "txt:\"(.*?)\"";
                            Pattern pattern = Pattern.compile(regex);
                            Matcher matcher = pattern.matcher(content);
                            if (matcher.find()) {
                                content = matcher.group(1);
                            }
                            if (TextUtils.isEmpty(content)) {
                                continue;
                            }
                            tempObject.put("content", content);
                        } else if (TextUtils.equals("image", type.toLowerCase()) && content.contains(",")) {
                            String[] strings = content.split(",");
                            int size = strings.length;
                            for (int n = 0; n < size; n++) {
                                String temp = strings[n].trim();
                                String value = temp.substring(temp.indexOf(":")).trim();
                                if (temp.startsWith(IMAGE)) {
                                    tempObject.put("fileName", value);
                                } else if (temp.startsWith(REMOTEURL)) {
                                    tempObject.put("remoteUrl", value);
                                } else if (temp.startsWith(THUMBNAIL)) {
                                    tempObject.put("thumbnail", value);
                                } else if (temp.startsWith(LOCALURL)) {
                                    tempObject.put("localUrl", value);
                                }
                            }
                        } else {
                            tempObject.put("content", content);
                        }
                        jsonArray.put(tempObject);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            }
            new Thread(new Runnable() {

                @Override
                public void run() {
                    Handler handler = new Handler(Looper.getMainLooper());
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            String message = jsonArray.toString();
                            Log.d(TAG, "============post back==================:" + message);
                            if (mEventSink != null) {
                                mEventSink.success(message);
                            }
                        }
                    });
                }
            }).start();
        }

        @Override
        public void onCmdMessage(List<Message> list) {
            //收到命令消息，命令消息不存数据库，一般用来作为系统通知，例如留言评论更新，
            //会话被客服接入，被转接，被关闭提醒
            Log.d(TAG, "===========onCmdMessage=========");
        }

        @Override
        public void onMessageStatusUpdate() {
            //消息的状态修改，一般可以用来刷新列表，显示最新的状态
            Log.d(TAG, "===========onMessageStatusUpdate=========");
        }

        @Override
        public void onMessageSent() {
            //发送消息后，会调用，可以在此刷新列表，显示最新的消息
            Log.d(TAG, "===========onMessageSent=========");
        }
    };

    private ChatManager.VisitorWaitListener mVisitorWaitListener = new ChatManager.VisitorWaitListener() {
        @Override
        public void waitCount(final int num) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    Handler handler = new Handler(Looper.getMainLooper());
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            if (mEventSink != null) {
                                mEventSink.success(num);
                            }
                        }
                    });
                }
            }).start();
        }
    };

    @Override
    public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
        mMethodChannel = new MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), "flutter_kefu_plugin");
        mApplication = (Application) flutterPluginBinding.getApplicationContext();
        mMethodChannel.setMethodCallHandler(this);
        mEventChannel = new EventChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), "flutter_kefu_plugin_event_channel");
        mEventChannel.setStreamHandler(this);
    }

    @Override
    public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
        mMethodChannel.setMethodCallHandler(null);
    }

    public FlutterKefuPlugin initPlugin(MethodChannel methodChannel, Registrar registrar) {
        mMethodChannel = methodChannel;
        mApplication = (Application) registrar.context().getApplicationContext();
        mActivity = new WeakReference<>(registrar.activity());
        return this;
    }

    public FlutterKefuPlugin initEventChannelPlugin(EventChannel eventChannel, Registrar registrar) {
        mEventChannel = eventChannel;
        mApplication = (Application) registrar.context().getApplicationContext();
        mActivity = new WeakReference<>(registrar.activity());
        return this;
    }

    // This static function is optional and equivalent to onAttachedToEngine. It supports the old
    // pre-Flutter-1.12 Android projects. You are encouraged to continue supporting
    // plugin registration via this function while apps migrate to use the new Android APIs
    // post-flutter-1.12 via https://flutter.dev/go/android-project-migration.
    //
    // It is encouraged to share logic between onAttachedToEngine and registerWith to keep
    // them functionally equivalent. Only one of onAttachedToEngine or registerWith will be called
    // depending on the user's project. onAttachedToEngine or registerWith must both be defined
    // in the same class.
    public static void registerWith(Registrar registrar) {
        final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_kefu_plugin");
        channel.setMethodCallHandler(new FlutterKefuPlugin().initPlugin(channel, registrar));
        final EventChannel eventChannel = new EventChannel(registrar.messenger(), "flutter_kefu_plugin_event_channel");
        eventChannel.setStreamHandler(new FlutterKefuPlugin().initEventChannelPlugin(eventChannel, registrar));
    }

    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
        String callMethod = call.method;
        if (!TextUtils.isEmpty(callMethod)) {
            switch (callMethod) {
                case "getPlatformVersion":
                    result.success("Android " + android.os.Build.VERSION.RELEASE);
                    break;
                case "init":
                    init(call, result);
                    break;
                case "login":
                    login(call, result);
                    break;
                case "logout":
                    logout(call, result);
                    break;
                case "sendTextMessage":
                    sendTextMessage(call, result);
                    break;
                case "sendImageMessage":
                    sendImageMessage(call, result);
                    break;
                case "sendFileMessage":
                    sendFileMessage(call, result);
                    break;
                case "sendLocationMessage":
                    sendLocationMessage(call, result);
                    break;
                case "getLoginStatus":
                    getLoginStatus(call, result);
                    break;
                case "getUnreadMessagesCount":
                    getUnreadMessagesCount(call, result);
                    break;
                case "maskAllConversationsAsRead":
                    maskAllConversationsAsRead(call, result);
                    break;
                case "getConversationMessages":
                    getConversationMessages(call, result);
                    break;
                case "addMessageListener":
                    addMessageListener(call, result);
                    break;
                case "removeMessageListener":
                    removeMessageListener();
                    break;
                case "addVisitorWaitListener":
                    addVisitorWaitListener(call, result);
                    break;
                case "removeVisitorWaitListener":
                    removeVisitorWaitListener();
                    break;
                case "getAllMsgCount":
                    getAllMsgCount(call, result);
                    break;
                case "deleteConversation":
                    deleteConversation(call, result);
                    break;
                case "getWorkStatus":
                    getWorkStatus(call, result);
                    break;
                case "getEnterpriseWelcome":
                    getEnterpriseWelcome(call, result);
                    break;
                case "addConnectionListener":
                    addConnectionListener(call, result);
                    break;
                default:
                    result.notImplemented();
                    break;
            }
        }
    }

    @Override
    public void onAttachedToActivity(ActivityPluginBinding binding) {
        mActivity = new WeakReference<>(binding.getActivity());
    }

    @Override
    public void onDetachedFromActivityForConfigChanges() {

    }

    @Override
    public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {

    }

    @Override
    public void onDetachedFromActivity() {
        mActivity = null;
    }

    /**
     * 环信客服云sdk初始化
     *
     * @param call
     * @param result
     */
    public void init(@NonNull MethodCall call, @NonNull Result result) {
        boolean logEnable = false;
        if (call.hasArgument("logEnable")) {
            logEnable = (boolean) call.argument("logEnable");
        }
        String appKey = (String) call.argument("appKey");
        String tenantId = (String) call.argument("tenantId");

        ChatClient.Options options = new ChatClient.Options();
        //必填项，appkey获取地址：kefu.easemob.com，“管理员模式 > 渠道管理 > 手机APP”页面的关联的“AppKey”
        options.setAppkey(appKey);
        //必填项，tenantId获取地址：kefu.easemob.com，“管理员模式 > 设置 > 企业信息”页面的“租户ID”
        options.setTenantId(tenantId);
        options.setConsoleLog(logEnable);
        options.showVisitorWaitCount();
        ChatClient.getInstance().init(mApplication, options);
        result.success(true);
    }

    /**
     * 获取登录状态
     *
     * @param call
     * @param result
     */
    public void getLoginStatus(@NonNull MethodCall call, @NonNull Result result) {
        result.success(ChatClient.getInstance().isLoggedInBefore());
    }

    /**
     * 登录
     *
     * @param call
     * @param result
     */
    public void login(@NonNull MethodCall call, @NonNull final Result result) {
        String username = (String) call.argument("username");
        String password = (String) call.argument("password");
        ChatClient.getInstance().login(username, password, new Callback() {
            @Override
            public void onSuccess() {
                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        Handler handler = new Handler(Looper.getMainLooper());
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                result.success(true);
                            }
                        });
                    }
                }).start();
            }

            @Override
            public void onError(int i, String s) {

            }

            @Override
            public void onProgress(int i, String s) {

            }
        });
    }

    /**
     * 退出，登出后则无法收到客服发来的消息
     *
     * @param call
     * @param result
     */
    public void logout(@NonNull MethodCall call, @NonNull final Result result) {
        boolean unbindDeviceToken = true;
        if (call.hasArgument("unbindDeviceToken")) {
            unbindDeviceToken = (boolean) call.argument("unbindDeviceToken");
        }
        ChatClient.getInstance().logout(unbindDeviceToken, new Callback() {
            @Override
            public void onSuccess() {
                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        Handler handler = new Handler(Looper.getMainLooper());
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                result.success(true);
                            }
                        });
                    }
                }).start();
            }

            @Override
            public void onError(int i, String s) {

            }

            @Override
            public void onProgress(int i, String s) {

            }
        });
        removeMessageListener();
        removeVisitorWaitListener();
    }

    /**
     * 发送文本消息
     *
     * @param call
     * @param result
     */
    public void sendTextMessage(@NonNull MethodCall call, @NonNull final Result result) {
        String content = (String) call.argument("content");
        String toChatUsername = (String) call.argument("toChatUsername");
        Message message = Message.createTxtSendMessage(content, toChatUsername);
        ChatClient.getInstance().chatManager().sendMessage(message, new Callback() {
            @Override
            public void onSuccess() {
                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        Handler handler = new Handler(Looper.getMainLooper());
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                result.success(true);
                            }
                        });
                    }
                }).start();
            }

            @Override
            public void onError(int i, String s) {

            }

            @Override
            public void onProgress(int i, String s) {

            }
        });
    }

    /**
     * 发送图片信息
     *
     * @param call
     * @param result
     */
    public void sendImageMessage(@NonNull MethodCall call, @NonNull final Result result) {
        String filePath = (String) call.argument("filePath");
        boolean sendOriginalImage = (boolean) call.argument("sendOriginalImage");
        String toChatUsername = (String) call.argument("toChatUsername");
        //filePath为图片路径，sendOriginalImage是否发送原图，false为不发送原图(默认超过100k的图片都会压缩后发给对方)，需要发送原图传true， toChatUsername为IM服务号
        Message message = Message.createImageSendMessage(filePath, sendOriginalImage, toChatUsername);
        ChatClient.getInstance().chatManager().sendMessage(message, new Callback() {
            @Override
            public void onSuccess() {
                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        Handler handler = new Handler(Looper.getMainLooper());
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                result.success(true);
                            }
                        });
                    }
                }).start();
            }

            @Override
            public void onError(int code, String error) {

            }

            @Override
            public void onProgress(int progress, String status) {

            }
        });
    }

    /**
     * 发送文件信息
     *
     * @param call
     * @param result
     */
    public void sendFileMessage(@NonNull MethodCall call, @NonNull final Result result) {
        String filePath = (String) call.argument("filePath");
        String toChatUsername = (String) call.argument("toChatUsername");
        Message message = Message.createFileSendMessage(filePath, toChatUsername);
        ChatClient.getInstance().chatManager().sendMessage(message, new Callback() {
            @Override
            public void onSuccess() {
                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        Handler handler = new Handler(Looper.getMainLooper());
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                result.success(true);
                            }
                        });
                    }
                }).start();
            }

            @Override
            public void onError(int code, String error) {

            }

            @Override
            public void onProgress(int progress, String status) {

            }
        });
    }

    /**
     * 发送地理位置
     *
     * @param call
     * @param result
     */
    public void sendLocationMessage(@NonNull MethodCall call, @NonNull final Result result) {
        double latitude = (double) call.argument("latitude");
        double longitude = (double) call.argument("longitude");
        String locAddress = (String) call.argument("locAddress");
        String toChatUsername = (String) call.argument("toChatUsername");
        Message message = Message.createLocationSendMessage(latitude, longitude, locAddress, toChatUsername);
        ChatClient.getInstance().chatManager().sendMessage(message, new Callback() {
            @Override
            public void onSuccess() {
                new Thread(new Runnable() {

                    @Override
                    public void run() {
                        Handler handler = new Handler(Looper.getMainLooper());
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                result.success(true);
                            }
                        });
                    }
                }).start();
            }

            @Override
            public void onError(int code, String error) {

            }

            @Override
            public void onProgress(int progress, String status) {

            }
        });
    }

    /**
     * 获取未读消息数
     *
     * @param call
     * @param result
     */
    public void getUnreadMessagesCount(@NonNull MethodCall call, @NonNull Result result) {
        String toChatUsername = (String) call.argument("toChatUsername");
        Conversation conversation = ChatClient.getInstance().chatManager().getConversation(toChatUsername);
        int unreadMessagesCount = conversation.unreadMessagesCount();
        result.success(unreadMessagesCount);
    }

    /**
     * 所有未读消息数清零
     *
     * @param call
     * @param result
     */
    public void maskAllConversationsAsRead(@NonNull MethodCall call, @NonNull Result result) {
        ChatClient.getInstance().chatManager().markAllConversationsAsRead();
        result.success(true);
    }

    /**
     * 获取此会话的所有消息
     *
     * @param call
     * @param result
     */
    public void getConversationMessages(@NonNull MethodCall call, @NonNull Result result) {
        String toChatUsername = (String) call.argument("toChatUsername");
        Conversation conversation = ChatClient.getInstance().chatManager().getConversation(toChatUsername);
        List<Message> messages = conversation.getAllMessages();
        Log.d(TAG, "============getConversationMessages=========" + messages.toString());
        JSONArray jsonArray = new JSONArray();
        JSONObject tempObject = null;
        if (messages != null && messages.size() > 0) {
            int count = messages.size();
            for (int i = 0; i < count; i++) {
                tempObject = new JSONObject();
                try {
                    String content = messages.get(i).body().toString();
                    if (TextUtils.isEmpty(content)) {
                        continue;
                    }
                    tempObject.put("from", messages.get(i).from());
                    tempObject.put("to", messages.get(i).to());
                    String type = messages.get(i).getType() == null ? "TXT" : messages.get(i).getType().name();
                    tempObject.put("type", type);
                    tempObject.put("msgTime", messages.get(i).messageTime());
                    if (TextUtils.equals("txt", type.toLowerCase())) {
                        String regex = "txt:\"(.*?)\"";
                        Pattern pattern = Pattern.compile(regex);
                        Matcher matcher = pattern.matcher(content);
                        if (matcher.find()) {
                            content = matcher.group(1);
                        }
                        if (TextUtils.isEmpty(content)) {
                            continue;
                        }
                        tempObject.put("content", content);
                    } else if (TextUtils.equals("image", type.toLowerCase()) && content.contains(",")) {
                        String[] strings = content.split(",");
                        int size = strings.length;
                        for (int n = 0; n < size; n++) {
                            String temp = strings[n].trim();
                            String value = temp.substring(temp.indexOf(":") + 1).trim();
                            if (temp.startsWith(IMAGE)) {
                                tempObject.put("fileName", value);
                            } else if (temp.startsWith(REMOTEURL)) {
                                tempObject.put("remoteUrl", value);
                            } else if (temp.startsWith(THUMBNAIL)) {
                                tempObject.put("thumbnail", value);
                            } else if (temp.startsWith(LOCALURL)) {
                                tempObject.put("localUrl", value);
                            }
                        }
                    } else {
                        tempObject.put("content", content);
                    }
                    jsonArray.put(tempObject);
                } catch (JSONException e) {
                    e.printStackTrace();
                }
            }
        }
        String message = jsonArray.toString();
        Log.d(TAG, "============post back==================:" + message);
        result.success(message);
    }

    /**
     * 注册消息监听来接收消息
     *
     * @param call
     * @param result
     */
    public void addMessageListener(@NonNull MethodCall call, @NonNull final Result result) {
        ChatClient.getInstance().chatManager().addMessageListener(mMessageListener);
    }

    /**
     * 获取消息总数
     *
     * @param call
     * @param result
     */
    public void getAllMsgCount(@NonNull MethodCall call, @NonNull Result result) {
        String toChatUsername = (String) call.argument("toChatUsername");
        Conversation conversation = ChatClient.getInstance().chatManager().getConversation(toChatUsername);
        ////获取此会话在本地的所有的消息数量
        int allMsgCount = conversation.getAllMsgCount();
        result.success(allMsgCount);
    }

    /**
     * 删除会话
     *
     * @param call
     * @param result
     */
    public void deleteConversation(@NonNull MethodCall call, @NonNull Result result) {
        String username = (String) call.argument("username");
        boolean deleteMessages = (boolean) call.argument("deleteMessages");
        //删除和某个user会话，如果需要保留聊天记录，传false
        boolean flag = ChatClient.getInstance().chatManager().deleteConversation(username, deleteMessages);
        result.success(flag);
    }

    /**
     * 获取企业欢迎语
     *
     * @param call
     * @param result
     */
    public void getEnterpriseWelcome(@NonNull MethodCall call, @NonNull final Result result) {
        ChatClient.getInstance().chatManager().getEnterpriseWelcome(new ValueCallBack<String>() {
            @Override
            public void onSuccess(final String value) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Handler handler = new Handler(Looper.getMainLooper());
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                result.success(value);
                            }
                        });
                    }
                }).start();
            }

            @Override
            public void onError(int error, String errorMsg) {

            }
        });
    }

    /**
     * 添加监听排队人数
     * 首先，初始化时，需要调用option.showVisitorWaitCount(),然后添加WaitListener.
     *
     * @param call
     * @param result
     */
    public void addVisitorWaitListener(@NonNull MethodCall call, @NonNull final Result result) {
        ChatClient.getInstance().chatManager().addVisitorWaitListener(mVisitorWaitListener);
    }

    /**
     * 移除排队人数监听
     */
    public void removeVisitorWaitListener() {
        ChatClient.getInstance().chatManager().removeVisitorWaitListener(mVisitorWaitListener);
    }

    /**
     * 获取工作状态
     *
     * @param call
     * @param result
     */
    public void getWorkStatus(@NonNull MethodCall call, @NonNull final Result result) {
        String customerAccount = (String) call.argument("customerAccount");
        //是否显示留言信息(一般在上班显示联系客服界面,在下班情况下显示留言界面)
        //返回true 为下班状态, 返回false为上班状态
        ChatClient.getInstance().leaveMsgManager().getWorkStatus(customerAccount, new ValueCallBack<String>() {
            @Override
            public void onSuccess(final String value) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Handler handler = new Handler(Looper.getMainLooper());
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                result.success(value);
                            }
                        });
                    }
                }).start();
            }

            @Override
            public void onError(int error, String errorMsg) {

            }
        });
    }

    public void addConnectionListener(@NonNull MethodCall call, @NonNull final Result result) {
        ChatClient.getInstance().addConnectionListener(new ChatClient.ConnectionListener() {
            @Override
            public void onConnected() {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Handler handler = new Handler(Looper.getMainLooper());
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                result.success(true);
                            }
                        });
                    }
                }).start();
            }

            @Override
            public void onDisconnected(int errorcode) {

            }
        });
    }

    public void removeMessageListener() {
        ChatClient.getInstance().chatManager().removeMessageListener(mMessageListener);
    }

    @Override
    public void onListen(Object arguments, EventChannel.EventSink events) {
        mEventSink = events;
    }

    @Override
    public void onCancel(Object arguments) {
        FlutterKefuPlugin.mEventSink = null;
    }
}
